package com.yjp.spring;


import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
@SuppressWarnings("all")
public class YjpApplicationContext {
  //传入的类
  private Class configClass;
  //key=beanName,value=bean对象
  private ConcurrentHashMap<String,BeanDefinition>  beanDefinitionMap=new ConcurrentHashMap<>();
  //key=beanName,value=单例bean对象
  private ConcurrentHashMap<String,Object>  singletonObjects=new ConcurrentHashMap<>();
  //BeanPostProcessor也叫后置处理器，作用是在Bean对象在实例化和依赖注入完毕后，在显示调用初始化方法的前后添加我们自己的逻辑
  private ArrayList<BeanPostProcessor> beanPostProcessors=new ArrayList<>();
    public YjpApplicationContext(Class configClass) {
      this.configClass = configClass;
      //扫描beanDefinition
      if (configClass.isAnnotationPresent(ComponentScan.class)) {
        //能到java配置类对象ComponentScan扫描的值
        ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String path = componentScanAnnotation.value();
        path = path.replace(".", "/");//com/yjp/service
        File baseDir = null;
        try {
          baseDir = new File(YjpApplicationContext.class.getClassLoader().getResource(".").toURI());
        } catch (URISyntaxException e) {
          e.printStackTrace();
        }
        ClassLoader classLoader = YjpApplicationContext.class.getClassLoader();
        //获取service目录
        File file = new File(baseDir,path);
        if (file.isDirectory()) {
          for (File f : file.listFiles()) {
            //绝对路径
            String fileName = f.getAbsolutePath();
            if (fileName.endsWith(".class")) {
              //截取com\\yjp\service\XX
              String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
              className = className.replace("\\", ".");
              try {
                //获得类对象
                Class<?> aClass = classLoader.loadClass(className);
                if (aClass.isAnnotationPresent(Component.class)){
                  //判断当前类对象是否为BeanPostProcessor的子类
                  if (BeanPostProcessor.class.isAssignableFrom(aClass)){
                    BeanPostProcessor instance = (BeanPostProcessor) aClass.newInstance();
                    beanPostProcessors.add(instance);
                  }
                  //获取Compont注解上的值
                  Component component = aClass.getAnnotation(Component.class);
                  String beanName = component.value();
                  //给没有定义bean名的 初始化默认值
                  if (beanName.equals("")){
                    beanName= Introspector.decapitalize(aClass.getSimpleName());
                  }
                  BeanDefinition beanDefinition = new BeanDefinition();
                  beanDefinition.setType(aClass);
                  if (aClass.isAnnotationPresent(Scope.class)){
                    Scope scopeAnnotation = aClass.getAnnotation(Scope.class);
                   beanDefinition.setScope(scopeAnnotation.value());
                  }else {
                    beanDefinition.setScope("singleton");
                  }
                  //将bean的名字，和beanDefinition（包含类是否为单例，对象类型）放入到map集合中
                    beanDefinitionMap.put(beanName,beanDefinition);
                }
              } catch (ClassNotFoundException e) {
                e.printStackTrace();
              } catch (InstantiationException e) {
                e.printStackTrace();
              } catch (IllegalAccessException e) {
                e.printStackTrace();
              }
            }
          }
        }
      }
//      实例化bean
      for (String beanName : beanDefinitionMap.keySet()) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
          Object bean = createBean(beanName, beanDefinition);
          singletonObjects.put(beanName,bean);
        }

      }
    }

  private Object createBean(String beanName, BeanDefinition beanDefinition){
    Class cls = beanDefinition.getType();
    try {
      Object instance = cls.getConstructor().newInstance();
      //依赖注入
      for (Field f : cls.getDeclaredFields()) {
           if (f.isAnnotationPresent(Autowired.class)){
             f.setAccessible(true);
             f.set(instance,getBean(f.getName()));
           }
      }
      if (instance instanceof BeanNameAware){
        ((BeanNameAware) instance).setBeanName(beanName);
      }
      for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
        instance = beanPostProcessor.postProcessBeforeInitialization(beanName,instance);
      }
      if (instance instanceof InitializingBean){
        ((InitializingBean)instance).afterPropertiesSet();
      }
      for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
         instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
      }
      return instance;
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
   return null;

  }


  public Object getBean(String beanName){
      BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
      if (beanDefinition==null){
        throw new NullPointerException();
      }else {
        if ("singleton".equals(beanDefinition.getScope())){
          Object bean = singletonObjects.get(beanName);
          if (bean==null){
            Object o = createBean(beanName, beanDefinition);
            singletonObjects.put(beanName,o);
          }
          return bean;
        }else {
              return createBean(beanName,beanDefinition);
        }
      }

    }
}
